/*
 内核空间与用户空间的交互
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

//设备号
static dev_t dev_num;

//cdev
struct cdev cdev_test;

//class 类
struct class* class;
struct device* device;

//open
static int cdev_open(struct inode* inode, struct file* file)
{
    printk("cdev open sucess \n");
    return 0;
}


//write
static ssize_t cdev_write(struct file* file, const char __user* buf, size_t size, loff_t* off )
{
     //定义输入缓冲区
     char inbuf[1024] = {'\0'};
     if (size >= 1024)
     {
        printk("buffer over \n");
        return -1;
     }
     if(copy_from_user(inbuf, buf, size) != 0)
     {
        printk(KERN_EMERG "write failed\n");
        return -1;
     }
     return size;
}

//read
static ssize_t cdev_read(struct file* file,  char __user* buf, size_t size, loff_t* off)
{
    //定义内核空间数据
    char outbuf[1024] = "cdev_read sucess";
    //copy_to_user 内核向用户传递信息
    if (size >= 1024)
    {
        printk("buffer over \n");
        return -1;
    }

    if (copy_to_user(buf, outbuf, size) != 0)
    {
        printk("read failed \n");
        return -1;
    }
    return size;

}

// release
static int cdev_release(struct inode* inode, struct file* file)
{
    printk("cdev release \n");
    return 0;
}

//设备操作函数
struct file_operations cdev_ops ={
    .owner = THIS_MODULE,
    .open = cdev_open,
    .read = cdev_read,
    .write = cdev_write,
    .release = cdev_release
};

static int __init deliver_init(void)
{
    //注册字符设备
    int ret =0;

    //分配设备号
    ret = alloc_chrdev_region(&dev_num, 0, 1, "dev_num");
    if (ret < 0)
    {
        printk("KERN_EMERG alloc_number failed\n");
        return -1;
    }

    //初始化cdev
    cdev_test.owner = THIS_MODULE;
    cdev_init(&cdev_test, &cdev_ops);

    //注册到内核
    cdev_add(&cdev_test, dev_num, 1);

    //创建类
    class = class_create(THIS_MODULE, "class");

    //创建设备
    device = device_create(class, NULL, dev_num, NULL, "device");

    return 0;

}

static void __exit deliver_exit(void)
{
    //注销字符设备
    
    //注销设备号
    unregister_chrdev_region(dev_num, 1);

    //删除dev
    cdev_del(&cdev_test);

    //删除设备
    device_destroy(class, dev_num);
    
    //删除类
    class_destroy(class);
}


module_init(deliver_init);
module_exit(deliver_exit);

MODULE_LICENSE("GPL");